package com.ats.audiotoscore;

import java.io.*;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.preference.PreferenceManager;
//import android.util.Log;
import android.view.*;
import android.view.ViewGroup.LayoutParams;
import android.widget.*;
import android.widget.SeekBar.OnSeekBarChangeListener;

import ar.com.daidalos.afiledialog.*;
import com.ats.audiotoscore.AudioCaptureCallback;

public class MainActivity extends Activity implements AudioCaptureCallback {
//	private static final String TAG = "AudioToScore";
	private PitchDetection pd = null;
	private AudioCapture ac = null;
	private AudioProcess ap = null;
	private SpectrumView spView = null;
	private MusicSheetView msView = null;
	private SeekBar seekBar = null;
	private String filename = null;
	private boolean devMode = true;

	public void OnSamplesUpdate(final double samples[], final int sampleRate, final long msTime) {
		if (ap == null)
			return;

		ap.UpdateSamples(samples, sampleRate, msTime);
	}

	public void AddNote(int note, long mstime, long duration) {
		msView.AddNote(note, mstime, duration);
		
		seekBar.setMax(msView.GetLimitIndex());
		if (seekBar.getProgress() == seekBar.getMax() - 1)
			seekBar.setProgress(seekBar.getMax());
	}

	public void UpdateUI() {
		MainActivity.this.runOnUiThread(new Runnable() {
	        public void run() {
	        	if (ac != null) {
	        		if (spView.getVisibility() == View.VISIBLE) {
	        			spView.DrawSamples(pd, ac, ap);
	        		}
	        		msView.UpdateSheet();
	        	}
	        }
	    });
	}

	@TargetApi(Build.VERSION_CODES.HONEYCOMB)
	private void initStrictMode() {
		if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB)
			return;

		StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectDiskReads()
                .detectDiskWrites()
                .detectNetwork()   // or .detectAll() for all detectable problems
                .penaltyLog()
                .build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects()
                .detectLeakedClosableObjects()
                .penaltyLog()
                .penaltyDeath()
                .build());
	}

	@Override
    protected void onCreate(Bundle savedInstanceState) {
		devMode = Utils.IsDebugMode(this.getApplicationContext());
   	    if (devMode) {
   	    	initStrictMode();
   	    }

   	    super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        msView = (MusicSheetView)this.findViewById(R.id.musicSheetView1);
		spView = (SpectrumView)this.findViewById(R.id.spectrumView1);
		seekBar = (SeekBar) findViewById(R.id.seekBar);
		seekBar.setOnSeekBarChangeListener( new OnSeekBarChangeListener()
		{
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
			{
				msView.SeekTo(progress);
			}

			public void onStartTrackingTouch(SeekBar seekBar)
			{
				
			}

			public void onStopTrackingTouch(SeekBar seekBar)
			{
				
			}
		});
    }

    @Override
    protected void onStart() {
		super.onStart();

		SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
		String sampleRate = sharedPrefs.getString("prefSampleRate", "0");
		String pdAccuracy = sharedPrefs.getString("prefPitchDetectionAccuracy", "0");

		ac = new AudioCapture(this, filename,  Integer.parseInt(sampleRate));
        pd = new PitchDetection(Integer.parseInt(pdAccuracy));
        ap = new AudioProcess(pd, this);
    }

    @Override
    protected void onStop() {
    	super.onStop();
    	if (ac != null) {
    		try {
            	ac.terminate();
            	ac.join();
            	ac = null;
    		} catch (Exception e) {
				System.err.println(e);
    		}
    	}

    	if (ap != null) {
    		try {
            	ap.terminate();
            	ap.join();
            	ap = null;
    		} catch (Exception e) {
				System.err.println(e);
    		}
    	}

    	pd = null;
    }

    @Override
    protected void onResume() {
    	super.onResume();
//    	audioCapture.startRecording();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    	if (resultCode == Activity.RESULT_OK) {
            boolean fileCreated = false;
            String filePath = "";
            
            Bundle bundle = data.getExtras();
            if (bundle != null) {
            	if (bundle.containsKey(FileChooserActivity.OUTPUT_NEW_FILE_NAME)) {
            		fileCreated = true;
            		File folder = (File) bundle.get(FileChooserActivity.OUTPUT_FILE_OBJECT);
            		String name = bundle.getString(FileChooserActivity.OUTPUT_NEW_FILE_NAME);
            		filePath = folder.getAbsolutePath() + "/" + name;
            	} else {
            		fileCreated = false;
            		File file = (File) bundle.get(FileChooserActivity.OUTPUT_FILE_OBJECT);
            		filePath = file.getAbsolutePath();
            	}
            }
            
            String message = fileCreated? "File created" : "File opened";
            message += ": " + filePath;
            Toast toast = Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG);
            toast.show();

            filename = filePath;
        }
    }

    @Override
    protected void onPause() {
    	super.onPause();
//		audioCapture.stopRecording();
    }

    public void onTogglePlayPause(View view) {
    	if (ac.isRecording()) {
        	ac.stopRecording();
    	} else {
        	ac.startRecording();
    	}
    }

    public void onClearMusicSheet(View view) {
    	msView.Reset();
    	UpdateUI();
    }

    public boolean OpenWavefile(MenuItem item) {
		Intent intent = new Intent(this, FileChooserActivity.class);
        this.startActivityForResult(intent, 0);
        return true;
	}

	public boolean WriteMidifile(MenuItem item) {
		String file = Environment.getExternalStorageDirectory() + "/audiotoscore.mid";
		msView.MidiWriteFile(file);
        String message = "File created" + ": " + file;
        Toast toast = Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG);
        toast.show();
        return true;
	}

    public boolean ToggleSpectrum(MenuItem item) {
    	LinearLayout llView = (LinearLayout)this.findViewById(R.id.linearLayoutViews);
    	if (spView.getVisibility() == View.VISIBLE)
    	{
    		msView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0, 1.f));
    		spView.setLayoutParams(new LinearLayout.LayoutParams(0, 0));
    		spView.setVisibility(View.GONE);
    		item.setChecked(false); 
    	}
    	else
    	{
    		msView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, llView.getHeight() * 50 / 100));
    		spView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, llView.getHeight() * 35 / 100));
    		spView.setVisibility(View.VISIBLE);
    		item.setChecked(true); 
    	}
    	llView.invalidate();
    	return true;
    }

	@Override
	public boolean onOptionsItemSelected(MenuItem item) 
	{
		switch (item.getItemId()) {
		case R.id.action_load_wavefile:
			return OpenWavefile(item);

		case R.id.action_write_midifile:
			return WriteMidifile(item);

		case R.id.action_toggle_spectrum:
			return ToggleSpectrum(item);

       case R.id.action_settings:
            Intent i = new Intent(this, Preferences.class);
            startActivityForResult(i, 1);
            return true;

       default:
	    	return super.onOptionsItemSelected(item);
	    }
	}

	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);

        if (devMode == true) {
            MenuItem item = menu.findItem(R.id.action_toggle_spectrum);
            if (item != null) {
            	item.setVisible(true);
            }
        }

        return true;
    }
    
    @Override
    protected void onDestroy() {
    	super.onDestroy();
    }
}
